package crontab

import (
	"encoding/json"
	"fmt"
	"github.com/gofrs/uuid"
	ctrl_cali "github.com/wsw188440873/ctrl-cali"
	"github.com/wsw188440873/ctrl-cali/model"
	"github.com/wsw188440873/ctrl-cali/sailhero"
	types2 "github.com/wsw188440873/ctrl-cali/types"
	"iot-base/auth/api/logic"
	. "iot-base/auth/logger"
	"iot-base/auth/svc"
	types3 "iot-base/auth/types"
	"iot-base/auth/utils"
	"strconv"
	"time"
)

func runCaliTask(id string) error {
	defer func() {
		if f := recover(); f != nil {
			Log.Errorf("crontab panic err:=%v", f)
		}
	}()
	taskLogic := logic.NewTaskLogic()
	taskData, err := taskLogic.FindByCodeId(id)
	if err != nil {
		return err
	}

	// 检查任务是否在开启状态
	if taskData.Switch == "disable" {
		Log.Infof("crontab stop task_id [%v] status[%v]", taskData.ID, taskData.Switch)
		return nil
	}

	var params []types3.CaliParams
	_ = json.Unmarshal([]byte(taskData.Rule), &params)
	requestId, _ := uuid.NewV4()
	fmt.Println("开始运行定时任务了.", params[0])
	Log.Infof("[%v] crontab start", requestId.String())
	stationLogic := logic.NewStationLogic()

	thingId, err := stationLogic.GetThingIdByStationIdAndModelId(taskData.StationId, taskData.ModelId)
	if err != nil {
		return err
	}

	//校准仪
	caliId, err := stationLogic.GetThingIdByStationIdAndModelId(taskData.StationId, types3.CaloModelId)
	if err != nil {
		return err
	}
	cali, err := ctrl_cali.NewCali("sailhero", taskData.StationId, thingId, caliId, taskData.ModelId, strconv.FormatInt(time.Now().Unix(), 10))
	if err != err {
		return err
	}

	data := types2.CaliParams{
		GasType:   params[0].GasType,
		Number:    params[0].Number,
		Flow:      params[0].Flow,
		Ext:       params[0].Ext,
		Unit:      params[0].Unit,
		ValueTime: params[0].ValueTime,
	}
	updatePrams := map[string]interface{}{}
	var pid string

	// （这个任务比较特殊，需要运行7天，每天定时运行）
	if taskData.TaskType == types2.ZeroDriftAndSpanDrift {
		insetData := map[string]interface{}{
			"request_id": strconv.FormatInt(time.Now().Unix(), 10),
			"thing_id":   thingId,
			"station_id": taskData.StationId,
			"model_id":   taskData.ModelId,
		}
		// 创建 父任务
		pid, _ = addLog(taskData.TaskName, taskData.TaskType, taskData.TimeType, insetData)
		execPrams := GetZeroDriftAndSpanDriftParams(taskData.ExecTime)
		b, _ := json.Marshal(execPrams)
		updatePrams["sub_task_params"] = b
		// 给后面6天生成定时任务
		go ZeroDriftAndSpanDriftSubTask(taskData.CodeId, pid, execPrams)
		taskData.TaskName = "第1天任务"
	}
	//// 运行校准任务
	taskId, _ := cali.CaliTask(pid, taskData.TaskType, taskData.TaskName, taskData.TimeType, types2.GroupTask{
		Subtasks: []types2.CaliParams{data},
		TaskNum:  1,
	})
	if taskData.TaskType == types2.ZeroDriftAndSpanDrift {
		updatePrams["run_task_log_id"] = pid
	} else {
		updatePrams["run_task_log_id"] = taskId
	}

	// 更新正在运行 任务id
	_, _ = svc.Dao.TTasks.UpdateMap(id, updatePrams)
	return nil
}

// GetZeroDriftAndSpanDriftParams 获取参数.
func GetZeroDriftAndSpanDriftParams(execTime string) []map[string]string {
	date := time.Now()
	execParam := make([]map[string]string, 0, 6)
	for i := 1; i < 7; i++ {
		//todo test
		//dataStr := date.Add(time.Minute * 3 * time.Duration(i)).Format("2006-01-02 15:04:05")
		dataStr := date.AddDate(0, 0, i).Format("2006-01-02")
		dataStr += " " + execTime
		temp := map[string]string{
			"exec_time": dataStr,
			"group_id":  strconv.Itoa(i + 1),
		}
		execParam = append(execParam, temp)
	}
	return execParam
}

//ZeroDriftAndSpanDriftSubTask 零点漂移，和跨度漂移 子任务
//taskId 任务ID
//taskLogId 任务ID
func ZeroDriftAndSpanDriftSubTask(codeId string, taskLogId string, execParams []map[string]string) {
	if len(execParams) == 0 {
		return
	}
	for _, value := range execParams {
		Cron.AddSubTask(codeId, taskLogId, value)
	}
}

// runCaliSubTask 运行子任务
func runCaliSubTask(codeId string, taskLogId string, groupId string, execTime string) error {
	defer func() {
		if f := recover(); f != nil {
			Log.Errorf("runCaliSubTask panic err:=%v", f)
		}
	}()
	defer Cron.RemoveTaskStr(taskLogId + groupId) // 子任务是一次性的，运行之后就需要移除任务

	runDate, err := utils.StringToTime(execTime)
	if err != nil {
		return err
	}
	// 任务已经过期
	if runDate.Year() < time.Now().Year() {
		Cron.RemoveTaskStr(taskLogId + groupId)
		return nil
	}
	// 检查任务的状态是否在睡眠中
	taskLog, err := svc.Dao.TTaskLog.Find(taskLogId)
	if err != nil {
		return err
	}
	// 睡眠状态才能运行
	if taskLog.Status != sailhero.SleepStatus {
		Cron.RemoveTaskStr(taskLogId + groupId)
		return nil
	}
	// 查询任务
	taskLogic := logic.NewTaskLogic()
	taskData, err := taskLogic.FindByCodeId(codeId)
	if err != nil {
		return err
	}
	// 查询设备ID
	stationLogic := logic.NewStationLogic()
	thingId, err := stationLogic.GetThingIdByStationIdAndModelId(taskData.StationId, taskData.ModelId)
	if err != nil {
		return err
	}

	// 查询校准仪ID
	caliId, err := stationLogic.GetThingIdByStationIdAndModelId(taskData.StationId, types3.CaloModelId)
	if err != nil {
		return err
	}
	cali, err := ctrl_cali.NewCali("sailhero", taskData.StationId, thingId, caliId, taskData.ModelId, strconv.FormatInt(time.Now().Unix(), 10))
	if err != nil {
		return err
	}
	var params []types3.CaliParams
	err = json.Unmarshal([]byte(taskData.Rule), &params)
	if err != nil {
		return err
	}
	data := types2.CaliParams{
		GasType:   params[0].GasType,
		Number:    params[0].Number,
		Flow:      params[0].Flow,
		Ext:       params[0].Ext,
		Unit:      params[0].Unit,
		ValueTime: params[0].ValueTime,
	}

	// 运行校准任务
	taskName := fmt.Sprintf("第%v天任务", groupId)
	_, err = cali.CaliTask(taskLogId, taskData.TaskType, taskName, taskData.TimeType, types2.GroupTask{
		Subtasks: []types2.CaliParams{data},
		TaskNum:  1,
		GroupId:  groupId,
	})
	return err
}

func addLog(taskName string, taskType string, painType string, params map[string]interface{}) (string, error) {
	contentParams := make(map[string]interface{})
	contentParams["request_id"] = params["request_id"]
	contentParams["model_id"] = params["model_id"]
	contentParams["code"] = 0
	contentParams["msg"] = ""
	data := model.TaskLog{
		ID:         utils.AutoID(),
		ThingId:    params["thing_id"].(string),
		StationId:  params["station_id"].(string),
		TaskType:   taskType,
		Status:     0,
		ProcessNum: 7,
		CurrNum:    0,
		Msg:        "",
		TaskName:   taskName,
		PlanType:   painType,
		TaskStatus: "doing",
	}
	b, _ := json.Marshal(contentParams)
	_ = data.Content.Scan(b)
	taskLogId, err := model.Dao.TTask.Add(data)
	//同步记录到云端
	sendCloudAddTaskLog(data)
	return taskLogId, err
}

func sendCloudAddTaskLog(params model.TaskLog) {
	go func() {
		_, err := utils.SendCloudCmd("AddTaskLog", params)
		fmt.Println("sendCloudAddTaskLog", err)
		// todo 失败需要加入到重新同步队列
	}()
}
